
/******************************************************************************
 * MODULE     : new_breaker.hpp
 * DESCRIPTION: Page breaking
 * COPYRIGHT  : (C) 2016  Joris van der Hoeven
 *******************************************************************************
 * This software falls under the GNU general public license version 3 or later.
 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
 ******************************************************************************/

#ifndef NEW_BREAKER_H
#define NEW_BREAKER_H
#include "Line/lazy_vstream.hpp"
#include "iterator.hpp"
#include "skeleton.hpp"
#include "vpenalty.hpp"

struct new_breaker_rep {
  array<page_item> l;
  int              papyrus_mode;
  space            height;
  space            fn_sep;    // inter-footnote separation
  space            fnote_sep; // separation between footnote and main text
  space            float_sep; // separation between text or floats and floats
  font             fn;
  int              first_page;
  int              quality;

  bool last_page_flag; // FIXME

  array<space> body_ht;    // the heights of these page_items
  array<space> body_cor;   // top and bottom corrections of page_items
  array<space> body_tot;   // total heights up to a certain index
  array<space> foot_ht;    // the height of all footnotes for one page_item,
  array<space> foot_tot;   // the cumulated footnote height until here
  array<space> float_ht;   // the height of all floats for one page_item,
  array<space> float_tot;  // the cumulated float height until here
  array<space> wide_ht;    // height of wide floats/footnotes for page_item,
  array<space> wide_tot;   // the cumulated wide float/footnote height
  array<space> break_ht;   // extra height in case of page break
  array<int>   col_number; // number of columns
  array<int>   col_same;   // last line with same number of columns
  array<bool>  must_new;   // compulsory new pages
  array<bool>  must_break; // compulsory new pages or page breaks

  array<array<insertion>> ins_list; // all page insertions

  hashmap<path, path>     best_prev; // best previous break points
  hashmap<path, vpenalty> best_pens; // corresponding penalties
  hashmap<path, bool>     todo_list;
  hashmap<path, bool>     done_list;

  hashmap<path, array<path>> cache_uniform;
  hashmap<path, array<path>> cache_colbreaks;

  new_breaker_rep (array<page_item> l, space ph, int quality, space fn_sep,
                   space fnote_sep, space float_sep, font fn, int fp);

  insertion make_insertion (lazy_vstream lvs, path p);
  space     compute_space (path b1, path b2, bool wide_part= false);
  bool      last_break (path b);
  void      find_page_breaks (path i1);
  void      find_page_breaks ();
  vpenalty  format_insertion (insertion& ins, double stretch);
  vpenalty  format_pagelet (pagelet& pg, double stretch);
  vpenalty  format_pagelet (pagelet& pg, space ht, bool last_page);
  insertion make_insertion (int i1, int i2);
  bool      here_floats (path p);
  void      lengthen_previous (pagelet& pg, int pos, space done);
  pagelet   assemble (path start, path end, bool wide_part= false);
  void      assemble_skeleton (skeleton& sk, path end, int& offset);

  // Pages with multi-column content
  bool        has_columns (path b1, path b2, int nr);
  int         number_columns (path b1, path b2);
  bool        is_uniform (path b1, path b2);
  array<path> break_uniform (path b1, path b2);
  int         compute_penalty (path b);
  path        postpone_floats (path b1, path b2);
  path break_columns_ansatz (path b1, path b2, path ba, path bb, double fr);
  path search_leftwards (path b1, path b2, path b, double fr);
  path search_rightwards (path b1, path b2, path b, double fr);
  path break_columns_at (path b1, path b2, double fr);
  array<path> break_columns (path b1, path b2);
  void      compute_space (array<space> spcs, array<vpenalty> pens, space& spc,
                           vpenalty& pen);
  space     compute_space (path b1, path b2, vpenalty& pen);
  insertion make_multi_column (skeleton sk, int real_nr_cols);
  insertion make_multi_column (path b1, path b2);
  pagelet   assemble_multi_columns (path b1, path b2);
};

vpenalty as_vpenalty (SI diff);
bool     float_has (tree t, char c);
bool     float_here (tree t);
space    as_space (tree t);

#endif // NEW_BREAKER_H
